package app.exp;

import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.rygh.core.algorithm.PrecisionRecall;
import org.rygh.core.html.Html;
import org.rygh.core.html.table.HtmlTable;
import org.rygh.core.html.table.TableData;
import org.rygh.core.html.table.TableTuple;
import org.rygh.core.model.common.MapList;
import org.rygh.core.util.UIo;
import org.rygh.core.util.tex.TexTabular;
import org.rygh.core.xml.XmlPath;
import org.rygh.semantic.model.rdf.Entity;

import app.App;
import wsi.exp.Exp1SelectedTree;
import wsi.exp.Exp2TreeToEntity;
import wsi.exp.ExpFolderController;
import wsi.function.Function;
import wsi.function.FunctionController;
import wsi.function.RuntimeInfo;
import wsi.match.MatchProperty;
import wsi.script.AppConfig;
import wsi.script.AppXml;

public class exp2Merger extends App {

	static class Tuple {
		final Map<Function, XmlPath> auto1 = new HashMap<>();
		final Map<Function, XmlPath> gold1 = new HashMap<>();
		final Map<Function, Boolean> exp1 = new HashMap<>();

		final MapList<Function, MatchProperty> auto2 = new MapList<>();
		final MapList<Function, MatchProperty> gold2 = new MapList<>();
		final Map<Function, Boolean> exp2 = new HashMap<>();

		final String name;
		final File[] dirs;

		public Tuple(String name, File[] dirs) {
			this.name = name;
			this.dirs = dirs;

			for (File d : dirs)
				assert d.exists() : d.getAbsolutePath();
		}
	}

	public static void main(String[] args) {
		init();

		AppConfig.init();
		AppConfig ac = AppConfig.shared();

		final int size = 3;

		File dir;
		File[][] dirs = new File[size][2];

		String path = "experiments/exp";

		dir = ac.getRunsFolder().getParentFile();
		dirs[0][0] = new File(dir, "1119_s_yago_100_fb/" + path + "1");
		dirs[0][1] = new File(dir, "1119_s_yago_100_fb/" + path + "2");
		dirs[1][0] = new File(dir, "1117_s_mbz_100_fb/" + path + "1");
		dirs[1][1] = new File(dir, "1117_s_mbz_100_fb/" + path + "2");
		dirs[2][0] = new File(dir, "1120_s_imdb_100_fb/" + path + "1");
		dirs[2][1] = new File(dir, "1120_s_imdb_100_fb/" + path + "2");

		assert dirs[0][1].exists() : dirs[0][1].getAbsolutePath();

		Tuple[] tuples = new Tuple[size];
		tuples[0] = new Tuple(AppXml.YAGO, dirs[0]);
		tuples[1] = new Tuple(AppXml.MBZ, dirs[1]);
		tuples[2] = new Tuple(AppXml.IMDB, dirs[2]);

		exp2Merger e = new exp2Merger(tuples);
		e.load();
		e.save();

		bye();
	}

	private final Set<Function> functionSet = new HashSet<>();
	private final Tuple[] tuples;

	public exp2Merger(Tuple[] tuples) {
		this.tuples = tuples;
	}

	private void load() {
		Exp1SelectedTree exp1 = new Exp1SelectedTree();
		Exp2TreeToEntity exp2 = new Exp2TreeToEntity();
		File dir;

		for (Tuple t : tuples) {
			dir = ExpFolderController.shared().getGoldFolderForExp1(t.name);
			assert dir.exists() : dir.getAbsolutePath();

			exp1.loadXml1(t.dirs[0], t.auto1);
			exp1.loadGold1(dir, t.gold1);
			exp1.judge1(t.auto1, t.gold1, t.exp1);

			dir = ExpFolderController.shared().getGoldFolderForExp2(t.name);
			assert dir.exists() : dir.getAbsolutePath();

			exp2.loadXml2(t.dirs[1], t.auto2);
			exp2.loadGold2(dir, t.gold2);
			exp2.judge2(t.auto2, t.gold2, t.exp1, t.exp2);

			functionSet.addAll(t.auto2.keySet());
		}
	}

	private void save() {
		saveHtml();
		saveTex();
	}

	private void saveHtml() {
		TableData data = new TableData();
		TableTuple tuple;

		tuple = new TableTuple();
		data.add(tuple);

		tuple.add("Web Service", "Function", "Type");

		int i;

		for (i = 0; i < tuples.length; i++)
			tuple.add(tuples[i].name);

		//

		AppConfig ac = AppConfig.shared();

		for (Function function : functionSet) {
			tuple = new TableTuple();
			data.add(tuple);

			RuntimeInfo config = ac.getConfig(function);
			assert config != null : function.getFullName();

			Entity type = config.getType();
			String type_str = type == null ? "identifier" : type.getValue();

			tuple.add(function.getService(), function.getName(), type_str);

			for (Tuple j : tuples) {
				if (!j.gold2.containsKey(function))
					tuple.add("/");
				else {
					Boolean val1 = j.exp1.get(function);
					if (val1 == null) {
						tuple.add("exp1 null");
						continue;
					} else if (!val1) {
						tuple.add("exp1 false");
						continue;
					}

					Boolean val2 = j.exp2.get(function);

					if (val2 == null)
						tuple.add("exp2 null");
					else
						tuple.add(val2);
				}
			}
		}

		data.sort(2);

		//

		Html html = new Html("Experiment 2");
		html.addElement(AppConfig.shared().getConfigHtml());

		HtmlTable table = new HtmlTable("Experiment 2 merged", data);
		html.addElement(table);

		String htmlstr = html.toString();

		for (Tuple t : tuples)
			UIo.saveFile(new File(t.dirs[1].getParentFile(),
					ExpFolderController.EXP + "2_result_2.html"), htmlstr);
	}

	private void saveTex() {
		final int l = tuples.length;

		TableData[] dataset = new TableData[l];
		TableTuple[] tps;

		int i, j;

		tps = new TableTuple[l];

		for (i = 0; i < l; i++) {
			dataset[i] = new TableData();
			tps[i] = new TableTuple();

			dataset[i].add(tps[i]);

			tps[i].add("Type");

			for (j = 0; j < 2; j++)
				tps[i].add(tuples[i].name);
		}

		//

		tps = new TableTuple[l];

		// for (i = 0; i < l; i++) {
		// tps[i] = new TableTuple();
		// dataset[i].add(tps[i]);
		//
		// tps[i].add("");
		//
		// tps[i].add("Prec.");
		// tps[i].add("Rec.");
		// }

		//

		FunctionController fc = FunctionController.shared();
		MapList<String, Function> mapList = FunctionController.shared()
				.getFunctionByInputTypeMap();
		PrecisionRecall[] prs = new PrecisionRecall[tuples.length];
		int gold_size, correct_size, answer_size;
		String fid;

		for (Entry<String, List<Function>> e : mapList.entrySet()) {
			String id = e.getKey();

			tps = new TableTuple[l];

			for (i = 0; i < l; i++) {
				tps[i] = new TableTuple();
				dataset[i].add(tps[i]);
				tps[i].add(id);
			}

			for (j = 0; j < l; j++) {
				Tuple t = tuples[j];
				gold_size = 0;

				for (Function f : t.gold2.keySet()) {
					fid = fc.getInputType(f);

					if (fid == null) {
						System.out.printf("[warn] skipped %s, %s\n", t.name,
								f.getFullName());
						continue;
					}

					if (fid.equals(id)) {
						gold_size++;
						System.out.printf("[info] gold (%d) %s %s: %s\n",
								gold_size, id, t.name, f.getFullName());
					}
				}

				prs[j] = new PrecisionRecall(gold_size);
			}

			for (j = 0; j < l; j++) {
				Tuple t = tuples[j];
				correct_size = 0;
				answer_size = 0;

				for (Function f : e.getValue()) {
					if (!t.auto2.containsKey(f))
						continue;

					answer_size++;

					Boolean val = t.exp2.get(f);

					if (val != null && val)
						correct_size++;
				}

				prs[j].setRelevant(correct_size);
				prs[j].setRetrieved(answer_size);

				System.out.printf("[info] p&r %s %s: %s\n", id, t.name,
						prs[j].toString());
			}

			for (j = 0; j < l; j++) {
				if (prs[j].getGoldSize() == 0) {
					dataset[j].remove(tps[j]);
				} else {
					tps[j].add(String.format("%.0f",
							prs[j].getPrecisionInPercentage()));
					tps[j].add(String.format("%.0f",
							prs[j].getRecallInPercentage()));
				}
			}

		}

		for (Tuple t : tuples) {
			File dir0 = new File(t.dirs[0].getParent(), "exp0");

			for (i = 0; i < l; i++) {
				dataset[i].sort(false);

				UIo.saveFile(
						new File(dir0, String.format("exp2_aggr_%d.html", i)),
						new HtmlTable("Aggregated", dataset[i])
								.toSimpleString());

				UIo.saveFile(
						new File(dir0, String.format("exp2_aggr_%d.tex", i)),
						new TexTabular(dataset[i]).toTexBodyString());
			}
		}
	}
}
